﻿using System;
using System.Drawing;
using System.Text;
using System.Net;
using System.IO;

namespace Channelvn.Storage
{
    /// <summary>
    /// Download viewsource of Html from URL
    /// Download ImageDate from URL
    /// </summary>
    /// <history>
    /// 26/03/2009 created by tuantmyb@gmail.com
    /// 13/10/2009 updated by tuantmyb@gmail.com
    /// </history>
    public class DownloadExpress
    {
        #region Field
        private string _Url = String.Empty;
        private string _UserAgent = String.Empty;
        private bool _SaveSession = false;
        private Encoding _EncodingType = null;

        public CookieCollection _cookiesCollect;
        private HttpWebRequest _webreq = null;
        private HttpWebResponse _webresponse = null;
        private CookieContainer _cookieContainer;
        private HttpStatusCode _HttpStatusCode;
        private string _Referer;

        #endregion

        #region Property
        public string Url
        {
            get { return _Url; }
            set { _Url = value; }
        }

        public string Referer
        {
            get { return _Referer; }
            set { _Referer = value; }
        }

        public string UserAgent
        {
            get { return _UserAgent; }
            set { _UserAgent = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool SaveSession
        {
            get { return _SaveSession; }
            set { _SaveSession = value; }
        }

        public Encoding EncodingType
        {
            get { return _EncodingType; }
            set { _EncodingType = value; }
        }

        public HttpWebRequest WebRequest
        {
            get { return _webreq; }
            set { _webreq = value; }
        }

        public HttpWebResponse WebResponse
        {
            get { return _webresponse; }
            set { _webresponse = value; }
        }
        /// <summary>
        /// 
        /// </summary>
        public HttpStatusCode StatusCode
        {
            get { return _HttpStatusCode; }
        }
        #endregion

        #region Constructor
        /// <summary>
        /// 
        /// </summary>
        public DownloadExpress()
        {
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="url">Url</param>
        public DownloadExpress(string url)
        {
            _Url = url;
            InitialWebRequest(_Url);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="url">Url</param>
        /// <param name="UrlRefer">Url Refer</param>
        public DownloadExpress(string url, string UrlRefer)
        {
            _Url = url;
            _Referer = UrlRefer;
            InitialWebRequest(_Url, _Referer);
        }
        #endregion


        

        #region Html process Methods

        /// <summary>
        /// Get Html Data from GET Methods
        /// </summary>
        /// <param name="url">url</param>
        /// <returns>Html Data of viewsource</returns>
        public string GetHtmlData(string url)
        {
            if (!url.Equals(_Url))
            {
                _Url = url;
                InitialWebRequest(url);    
            }
            return GetHtmlData();
        }

        /// <summary>
        /// Get Html Data from GET Methods
        /// </summary>
        /// <returns>view source of url</returns>
        public string GetHtmlData()
        {
            string htmlData = null;
            if (string.IsNullOrEmpty(Url) || !Url.Contains("http://"))
            {
                return htmlData;
            }
            try
            {
                _webreq.Method = "GET";
                _webreq.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                _webreq.Headers.Add(HttpRequestHeader.AcceptEncoding, "identity");
                _webreq.AllowAutoRedirect = true;
                _webreq.MaximumAutomaticRedirections = 3;
                GetResponseAndStreamData(ref htmlData);
            }
            catch (Exception ex) {
                throw ex;
            }
            return htmlData;
        }

        /// <summary>
        /// Get Html Data from GET Methods
        /// </summary>
        /// <param name="url"></param>
        /// <param name="cookieCon"></param>
        /// <returns>view source of url</returns>
        public string GetHtmlData(string url, CookieCollection cookieCon)
        {
            string htmlData = null;
            if (string.IsNullOrEmpty(Url) || !Url.Contains("http://"))
            {
                return htmlData;
            }
            try
            {
                InitialWebRequest(url);
                _webreq.Method = "GET";
                _webreq.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                _webreq.Headers.Add(HttpRequestHeader.AcceptEncoding, "identity");
                _webreq.AllowAutoRedirect = true;
                _webreq.MaximumAutomaticRedirections = 3;
                GetResponseAndStreamData(ref htmlData, cookieCon);
            }
            catch (Exception exc) { }
            return htmlData;
        }


        /// <summary>
        /// Get Html Data from GET Methods
        /// </summary>
        /// <param name="url"></param>
        /// <param name="referer"></param>
        /// <returns>view source of url</returns>
        public string GetHtmlData(string url, string referer)
        {
            string htmlData = null;
            if (string.IsNullOrEmpty(Url) || !Url.Contains("http://"))
            {
                return htmlData;
            }
            try
            {
                InitialWebRequest(url, referer);
                _webreq.Method = "GET";
                _webreq.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                _webreq.Headers.Add(HttpRequestHeader.AcceptEncoding, "identity");
                _webreq.AllowAutoRedirect = true;
                _webreq.MaximumAutomaticRedirections = 3;
                GetResponseAndStreamData(ref htmlData, _cookiesCollect);
            }
            catch (Exception exc) { }
            return htmlData;
        }

       


        /// <summary>
        /// Get Html Data from POST Methods
        /// </summary>
        /// <param name="url">url</param>
        /// <param name="postdata">string to post</param>
        /// <returns>viewsource of Html Data</returns>
        public string GetHtmlPostData(string url, string postdata)
        {
            _Url = url;
            InitialWebRequest(url);
            return GetHtmlPostData(postdata);
        }

        /// <summary>
        /// Get Html Data from POST Methods
        /// </summary>
        /// <param name="postdata">string to post</param>
        /// <returns>viewsource of Html Data </returns>
        /// <example>
        /// postdata: 3 object:obj=Cat,Tmc9PQ,showAll,new ; page=3 ; view=1 
        /// string to Post: obj=Cat,Tmc9PQ,showAll,new&page=3&view=1
        /// </example>
        public string GetHtmlPostData(string postdata)
        {
            string htmlData = null;
            try
            {
                // Prepare web request...
                _webreq.Method = "POST";
                _webreq.Accept = "*/*";
                _webreq.ContentType = "application/x-www-form-urlencoded";//only use for Post data
                byte[] data = Encoding.UTF8.GetBytes(postdata);
                try
                {
                    _webreq.ContentLength = data.Length;    
                }
                catch{}
                
                //_webreq.UseDefaultCredentials = true;
                Stream newStream = _webreq.GetRequestStream();
                // Send the data.
                newStream.Write(data, 0, data.Length);
                newStream.Close();
                GetResponseAndStreamData(ref htmlData);
            }
            catch
            {
                return null;
            }
            return htmlData;
        }

        public string GetHtmlPostDataCafeF(string postdata)
        {
            string htmlData = null;
            try
            {
                // Prepare web request...
                _webreq.Method = "POST";
                _webreq.Accept = "*/*";
                _webreq.ContentType = "multipart/form-data";//only use for Post data
                byte[] data = Encoding.UTF8.GetBytes(postdata);
                try
                {
                    _webreq.ContentLength = data.Length;
                }
                catch (Exception ex) { }

                //_webreq.UseDefaultCredentials = true;
                Stream newStream = _webreq.GetRequestStream();
                // Send the data.
                newStream.Write(data, 0, data.Length);
                newStream.Close();
                GetResponseAndStreamData(ref htmlData);
            }
            catch (Exception ex1)
            {
                return null;
            }
            return htmlData;
        }



        /// <summary>
        /// Get Html Data from POST Methods
        /// </summary>
        /// <param name="postdata">string to post</param>
        /// <returns>viewsource of Html Data </returns>
        /// <example>
        /// postdata: 3 object:obj=Cat,Tmc9PQ,showAll,new ; page=3 ; view=1 
        /// string to Post: obj=Cat,Tmc9PQ,showAll,new&page=3&view=1
        /// </example>
        public string GetHtmlPostData(string postdata, CookieCollection cookieCon)
        {
            string htmlData = null;
            try
            {
                // Prepare web request...
                _webreq.Method = "POST";
                _webreq.Accept = "*/*";
                _webreq.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; //"application/x-www-form-urlencoded";//only use for Post data
                byte[] data = Encoding.UTF8.GetBytes(postdata);
                try
                {
                    _webreq.ContentLength = data.Length;
                }
                catch { }

                //_webreq.UseDefaultCredentials = true;
                Stream newStream = _webreq.GetRequestStream();
                // Send the data.
                newStream.Write(data, 0, data.Length);
                newStream.Close();
                GetResponseAndStreamData(ref htmlData, cookieCon);
            }
            catch
            {
                return null;
            }
            return htmlData;
        }

        #endregion

        #region Image Process Methods
        /// <summary>
        /// Get Image Data from GET Methods
        /// </summary>
        /// <returns>view source of url</returns>
        public Image GetImageData()
        {
            Image imgData = null;
            if (string.IsNullOrEmpty(Url))
            {
                return imgData;
            }
            try
            {
                _webreq.Method = "GET";
                _webreq.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
                _webreq.Headers.Add(HttpRequestHeader.AcceptEncoding, "identity");
                _webreq.AllowAutoRedirect = true;
                _webreq.MaximumAutomaticRedirections = 3;
                //_webreq.AllowWriteStreamBuffering = true;//

                if (_SaveSession)
                {
                    _cookieContainer = new CookieContainer();
                    _webreq.CookieContainer = _cookieContainer;
                    //save Cookies Container
                    if (_cookiesCollect == null)
                        _cookiesCollect = new CookieCollection();

                    _cookieContainer.Add(_cookiesCollect);
                }
                GetResponseAndStreamImage(ref imgData);
            }
            catch (Exception exc)
            {
                throw exc;
            }
            return imgData;
        } 
        #endregion


        #region private methods
        private void InitialWebRequest(string url)
        {
            _webreq = (HttpWebRequest)System.Net.WebRequest.Create(url);
            _webreq.ContentType = "application/x-www-form-urlencoded";
            _webreq.UserAgent = _UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1";
            _webreq.Headers.Add(HttpRequestHeader.AcceptLanguage, "en-us,en;q=0.5");
            _webreq.Headers.Add(HttpRequestHeader.AcceptCharset, "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
            _webreq.Timeout = 120000;//120seconds
            _webreq.KeepAlive = true;

            //ServicePointManager.ServerCertificateValidationCallback += delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
            //{
            //    return true; // **** Always accept
            //};
        }

        private void InitialWebRequest(string url, string UrlReferrer)
        {
            InitialWebRequest(url);
            _Referer = UrlReferrer;
            try
            {
                if (!string.IsNullOrEmpty(UrlReferrer))
                    _webreq.Referer = _Referer;
            }
            catch (Exception exc)
            {
                throw exc;
            }
        }

        /// <summary>
        /// Get Response And Stream Data for this url
        /// </summary>
        /// <param name="htmlData"></param>
        private void GetResponseAndStreamData(ref string htmlData)
        {
            if (_SaveSession)
            {
                //creat Cookies Container
                if (_cookieContainer == null)
                    _cookieContainer = new CookieContainer();
                _webreq.CookieContainer = _cookieContainer;
                //creat Cookies Collection
                if (_cookiesCollect == null)
                    _cookiesCollect = new CookieCollection();
                _cookieContainer.Add(_cookiesCollect);
            }
            try
            {
                // Sends the HttpWebRequest and waits for the response. 
                _webresponse = (HttpWebResponse)_webreq.GetResponse();
            }
            catch (WebException exc)
            {
                HttpWebResponse hresp = null;
                if (exc.Status == WebExceptionStatus.ProtocolError)
                {
                    hresp = exc.Response as HttpWebResponse;
                    htmlData = exc.ToString();
                }
                if (hresp != null)
                    _HttpStatusCode = hresp.StatusCode;
                //return;
                throw exc;
            }

            if (_SaveSession)
            {
                //Get Cookies from Lastest visitted
                _webresponse.Cookies = _webreq.CookieContainer.GetCookies(_webreq.RequestUri);

                //save Cookies Collection
                _cookiesCollect = new CookieCollection();//Clear it
                _cookiesCollect.Add(_webresponse.Cookies);
            }
            // Gets the stream associated with the response.
            Stream responseStream;
            try
            {
                responseStream = _webresponse.GetResponseStream();
            }
            catch (WebException exc)
            {
                HttpWebResponse hresp = null;
                if (exc.Status == WebExceptionStatus.ProtocolError)
                {
                    hresp = exc.Response as HttpWebResponse;
                    htmlData = exc.ToString();
                }
                if (hresp != null)
                    _HttpStatusCode = hresp.StatusCode;
                //return;
                throw exc;
            }
            _HttpStatusCode = _webresponse.StatusCode;

            // Pipes the stream to a higher level stream reader with the required encoding format. 
            StreamReader responseReaderStream = new StreamReader(responseStream, _EncodingType ?? Encoding.UTF8);

            htmlData = responseReaderStream.ReadToEnd();

            // Releases the resources of the response.
            _webresponse.Close();
            // Releases the resources of the Stream.
            responseStream.Close();
        }

        /// <summary>
        /// Get Response And Stream Data for this url
        /// </summary>
        /// <param name="htmlData"></param>
        /// <param name="cookiecollect"></param>
        private void GetResponseAndStreamData(ref string htmlData, CookieCollection cookiecollect)
        {

            //creat Cookies Container
            if (_cookieContainer == null)
                _cookieContainer = new CookieContainer();
            if (cookiecollect != null)
                _cookieContainer.Add(cookiecollect);
            else
                //creat Cookies Collection
                _cookiesCollect = new CookieCollection();
            _webreq.CookieContainer = _cookieContainer;

            try
            {
                // Sends the HttpWebRequest and waits for the response. 
                _webresponse = (HttpWebResponse)_webreq.GetResponse();
            }
            catch (WebException exc)
            {
                HttpWebResponse hresp = null;
                if (exc.Status == WebExceptionStatus.ProtocolError)
                {
                    hresp = exc.Response as HttpWebResponse;
                    htmlData = exc.ToString();
                }
                if (hresp != null)
                    _HttpStatusCode = hresp.StatusCode;
                return;
            }

            _webresponse.Cookies = _webreq.CookieContainer.GetCookies(_webreq.RequestUri);

            //save Cookies Collection
            _cookiesCollect = new CookieCollection();//Clear it
            _cookiesCollect.Add(_webresponse.Cookies);

            // Gets the stream associated with the response.
            Stream responseStream;
            try
            {
                responseStream = _webresponse.GetResponseStream();
            }
            catch (WebException exc)
            {
                HttpWebResponse hresp = null;
                if (exc.Status == WebExceptionStatus.ProtocolError)
                {
                    hresp = exc.Response as HttpWebResponse;
                    htmlData = exc.ToString();
                }
                if (hresp != null)
                    _HttpStatusCode = hresp.StatusCode;
                return;
            }
            _HttpStatusCode = _webresponse.StatusCode;

            // Pipes the stream to a higher level stream reader with the required encoding format. 
            StreamReader responseReaderStream = new StreamReader(responseStream, _EncodingType ?? Encoding.UTF8);

            htmlData = responseReaderStream.ReadToEnd();

            // Releases the resources of the response.
            _webresponse.Close();
            // Releases the resources of the Stream.
            responseStream.Close();
        }

        /// <summary>
        /// Get Response And Stream Image for this url
        /// </summary>
        /// <param name="imgData"></param>
        private void GetResponseAndStreamImage(ref Image imgData)
        {
            if (_SaveSession)
            {
                //creat Cookies Container
                if (_cookieContainer == null)
                    _cookieContainer = new CookieContainer();
                //receive Cookies Container
                _webreq.CookieContainer = _cookieContainer;
                //creat Cookies Collection
                if (_cookiesCollect == null)
                    _cookiesCollect = new CookieCollection();
                _cookieContainer.Add(_cookiesCollect);
            }
            // Sends the HttpWebRequest and waits for the response. 
            _webresponse = (HttpWebResponse)_webreq.GetResponse();


            if (_SaveSession)
            {
                //Get Cookies from Lastest visitted
                _webresponse.Cookies = _webreq.CookieContainer.GetCookies(_webreq.RequestUri);
                //save Cookies Collection
                _cookiesCollect = new CookieCollection();//Clear it
                _cookiesCollect.Add(_webresponse.Cookies);
            }
            // Gets the stream associated with the response.
            Stream responseStream = _webresponse.GetResponseStream();

            imgData = Image.FromStream(responseStream);

            // Releases the resources of the response.
            _webresponse.Close();
            // Releases the resources of the Stream.
            responseStream.Close();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="webresponse"></param>
        /// <returns></returns>
        public virtual string GetRedirectURL(HttpWebResponse webresponse)
        {
            string uri = "";
            WebHeaderCollection headers = webresponse.Headers;

            if ((webresponse.StatusCode == HttpStatusCode.Found) ||
                (webresponse.StatusCode == HttpStatusCode.Redirect) ||
                (webresponse.StatusCode == HttpStatusCode.Moved) ||
                (webresponse.StatusCode == HttpStatusCode.MovedPermanently))
            {
                // Get redirected uri
                uri = headers["Location"];
                uri = uri.Trim();
            }
            else
            {
                if (!string.IsNullOrEmpty(webresponse.ResponseUri.ToString()))
                    return webresponse.ResponseUri.ToString();
            }

            ////Check for any cookies
            //if (headers["Set-Cookie"] != null)
            //{
            //    Cookie = headers["Set-Cookie"];
            //}
            //                string StartURI = "http:/";

            //                if (uri.Length > 0 && uri.StartsWith(StartURI)==false)

            //                {

            //                      uri = StartURI + uri;

            //                }

            return uri;
        } 
        #endregion
    }
}